package wrapper;
import anno.TableField;
import emun.MatchCondition;
import interfaces.Compare;
import interfaces.SFunction;
import segements.MergeSegment;
import segements.MergeSegmentList;
import toolkit.LambdaUtils;
import toolkit.SerializedLambda;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;


/**
 * <ul>
 * <li>Title: AbstractWrapper</li>
 * <li>Description: TODO </li>
 * </ul>
 *
 * @author 程序员ken
 * @date 2021/4/28 0028 下午 16:23
 */
//extends Wrapper<T>
public abstract class AbstractWrapper<T, R, This extends  AbstractWrapper>
        implements Compare<This, R> {

    protected MergeSegmentList expression;
    protected Map<String, Object> paramNameValuePairs;

    public Class<T> entityClass;
    private Map<String, String> columnMap = null;
    private boolean initColumnMap = false;



    public AbstractWrapper() {
    }

    //实际实现
    @Override
    public This eq(boolean condition, R column, Object val) {
        String fileName = columnToString((SFunction) column);
        MergeSegment segment = new MergeSegment();
        segment.setColumName(fileName);
        segment.setColumValue(val);
        segment.setMatchCondition(MatchCondition.EQ);
        expression.add(segment);
        paramNameValuePairs.putIfAbsent(fileName,val);
        return (This)this;
    }

    @Override
    public This ne(boolean condition, R column, Object val) {
        String fileName = columnToString((SFunction) column);
        MergeSegment segment = new MergeSegment();
        segment.setColumName(fileName);
        segment.setColumValue(val);
        segment.setMatchCondition(MatchCondition.NE);
        expression.add(segment);
        paramNameValuePairs.putIfAbsent(fileName,val);
        return (This)this;
    }

    @Override
    public This gt(boolean condition, R column, Object val) {
        String fileName = columnToString((SFunction) column);
        MergeSegment segment = new MergeSegment();
        segment.setColumName(fileName);
        segment.setColumValue(val);
        segment.setMatchCondition(MatchCondition.GT);
        expression.add(segment);
        paramNameValuePairs.putIfAbsent(fileName,val);
        return (This)this;
    }

    @Override
    public This lt(boolean condition, R column, Object val) {
        String fileName = columnToString((SFunction) column);
        MergeSegment segment = new MergeSegment();
        segment.setColumName(fileName);
        segment.setColumValue(val);
        segment.setMatchCondition(MatchCondition.LT);
        expression.add(segment);
        paramNameValuePairs.putIfAbsent(fileName,val);
        return (This)this;
    }

    /***
     * 功能描述:  获取字段信息
     * @return: java.lang.String
     * @author: 程序员ken
     * @date: 2021/4/28 21:34
    */
    protected String columnToString(SFunction<T, ?> column) {
        SerializedLambda resolve = LambdaUtils.resolve(column);
        return this.getColumn(resolve);
    }


    private String getColumn(SerializedLambda lambda) {
        String fieldName = resolveFieldName(lambda.getImplMethodName());
        if (!this.initColumnMap || !this.columnMap.containsKey(fieldName)) {
            String entityClassName = lambda.getImplClassName();
            try{
                Class<T> aClass = (Class<T>)Class.forName(entityClassName.replaceAll("\\\\", "."));
                if(entityClass==null){
                    entityClass = aClass;
                }
                this.columnMap =  getColumnMap(aClass);
                //3.0.6 支持 ==>3.3.2 不支持
                //this.columnMap = LambdaUtils.getColumnMap(entityClassName);
                this.initColumnMap = true;
            }catch (Exception ex){

            }
        }
        return fieldName;
    }

    /**
     * 功能描述: 获取当前实体的“数据库”字段
     * @param aClass
     * @return: java.util.Map<java.lang.String,java.lang.String>
     * @author: 程序员ken
     * @date: 2021/4/29 0029 下午 12:39
    */
    protected  Map<String,String> getColumnMap(Class<?> aClass){
        Map<String,String> map = new HashMap<String,String>();
        //ClassLoader classLoader = aClass.getClassLoader();
        Field[] declaredFields = aClass.getDeclaredFields();
        TableField tableField =null;
        for (Field field:declaredFields) {
             tableField = field.getAnnotation(TableField.class);
             if(!(tableField!=null && !tableField.exist())){
                 map.putIfAbsent(field.getName(),field.getName());
             }
        }

        return map;
    }

    public static String resolveFieldName(String getMethodName) {
        if (getMethodName.startsWith("get")) {
            getMethodName = getMethodName.substring(3);
        } else if (getMethodName.startsWith("is")) {
            getMethodName = getMethodName.substring(2);
        }
        return firstToLowerCase(getMethodName);
    }

    public static String firstToLowerCase(String param) {
        return param==null || "".equals(param.trim()) ? "" :
                param.substring(0, 1).toLowerCase() + param.substring(1);
    }





}
